
// RefreeRetrievalDlg.cpp : implementation file
//

#include "stdafx.h"
#include "RefreeRetrieval.h"
#include "RefreeRetrievalDlg.h"
#include "../PatchCluster/Data/CodeBook.h"
#include "../PatchCluster/Xml/TextFile.h"
#include "../PatchCluster/Xml/Markup.h"
#include "ViewBitmapDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()

/*==============================================================*/
// CRefreeRetrievalDlg dialog
/*==============================================================*/


void CRefreeRetrievalDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_TXTINPUTVIDEO, m_txtInputVideo);
	DDX_Control(pDX, IDC_BTNINPUTVIDEO, m_btnInputVideo);
	DDX_Control(pDX, IDC_TXTCLUSTERMODEL, m_txtClusterModel);
	DDX_Control(pDX, IDC_BTNCLUSTERMODEL, m_btnClusterModel);
	DDX_Control(pDX, IDC_LSTFRAMES, m_lstFrames);
	DDX_Control(pDX, IDC_EDTCLUSTERTHRESHOLD, m_txtClusterThreshold);
	DDX_Control(pDX, IDC_EDTPATCHSIZE, m_txtPatchSize);
	DDX_Control(pDX, IDC_SPINPATCHSIZE, m_spinPatchSize);
	DDX_Control(pDX, IDC_CMBPATCHMODE, m_cmbPatchMode);
	DDX_Control(pDX, IDC_EDTREGIONTHRESHOLD, m_txtRegionThreshold);
	DDX_Control(pDX, IDC_SPINREGIONTHRESHOLD, m_spinRegionThreshold);
	DDX_Control(pDX, IDC_PICCTRL, m_picVideo);
	DDX_Control(pDX, IDC_BTNPAUSE, m_btnPause);
	DDX_Control(pDX, IDOK, m_btnStart);
	DDX_Control(pDX, IDCANCEL, m_btnExit);
	DDX_Control(pDX, IDC_LBLFRAMES, m_lblFrames);
	DDX_Control(pDX, IDC_SPINTHREADCOUNT, m_spinThreadCount);
	DDX_Control(pDX, IDC_EDTTHREADCOUNT, m_txtThreadCount);
	DDX_Control(pDX, IDC_TXTSIFTKMEANSMODEL, m_txtSIFTKmeansModel);
	DDX_Control(pDX, IDC_TXTSIFTSVMMODEL, m_txtSIFTSVMModel);
}

BEGIN_MESSAGE_MAP(CRefreeRetrievalDlg, CDialog)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	//}}AFX_MSG_MAP
	ON_BN_CLICKED(IDC_BTNINPUTVIDEO, &CRefreeRetrievalDlg::OnBnClickedBtninputvideo)
	ON_BN_CLICKED(IDC_BTNCLUSTERMODEL, &CRefreeRetrievalDlg::OnBnClickedBtnclustermodel)
	ON_BN_CLICKED(IDOK, &CRefreeRetrievalDlg::OnBnClickedOk)
	ON_MESSAGE(WM_APP_GRAPHNOTIFY, OnVideoAnaGraphNotify)
	ON_MESSAGE(WM_USER_VIDEOANA, OnVideoAnaUserAnalysis)
	ON_MESSAGE(CRetrieverMaster::WM_NOTIFIERMESSAGE, OnRetrieverMessage)
	ON_BN_CLICKED(IDCANCEL, &CRefreeRetrievalDlg::OnBnClickedCancel)
	ON_BN_CLICKED(IDC_BTNPAUSE, &CRefreeRetrievalDlg::OnBnClickedBtnpause)
	ON_NOTIFY(LVN_ITEMACTIVATE, IDC_LSTFRAMES, &CRefreeRetrievalDlg::OnLvnItemActivateLstframes)
	ON_BN_CLICKED(IDC_BTNSIFTKMEANSMODEL, &CRefreeRetrievalDlg::OnBnClickedBtnsiftkmeansmodel)
	ON_BN_CLICKED(IDC_BTNSIFTSVMMODEL, &CRefreeRetrievalDlg::OnBnClickedBtnsiftsvmmodel)
END_MESSAGE_MAP()

CRefreeRetrievalDlg::CRefreeRetrievalDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CRefreeRetrievalDlg::IDD, pParent),
	m_codeBook(NULL),
	m_histExtractor(new CHistFeature())
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

CRefreeRetrievalDlg::~CRefreeRetrievalDlg()
{
	if(m_codeBook)
		delete m_codeBook;
	if(m_histExtractor)
		delete m_histExtractor;
	DeleteHBITMAPs(m_arrKeyFrames);
}

void CRefreeRetrievalDlg::EmptyImgList(CImageList& imgList)
{
	for(int i = imgList.GetImageCount() - 1; i >= 0; --i)
	{
		imgList.Remove(0);
	}
}

BOOL CRefreeRetrievalDlg::ReadParams(CString& sVideoFile, CString& sClusterModelFile,
				double& dClusterThreshold, int& iPatchSize, PatchMode& patchMode,
				int& regionThreshold, int& iThreadCount)
{
	// files
	m_txtInputVideo.GetWindowText(sVideoFile);
	m_txtClusterModel.GetWindowText(sClusterModelFile);
	sVideoFile = sVideoFile.Trim();
	sClusterModelFile = sClusterModelFile.Trim();

	if(sVideoFile.GetLength() == 0 || sClusterModelFile.GetLength() == 0)
	{
		::MessageBox(GetSafeHwnd(), L"Invalid input file(s).", L"Error", MB_ICONERROR);
		m_txtInputVideo.SetFocus();
		return FALSE;
	}

	// cluster threshold
	CString sClusterThreshold;
	m_txtClusterThreshold.GetWindowText(sClusterThreshold);
	dClusterThreshold = _wtof(sClusterThreshold);

	// patch size
	iPatchSize = m_spinPatchSize.GetPos32();

	// patch Mode
	PatchMode arr[3] = {PatchModeNonOverlapped, PatchModeHalfOverlapped, PatchModePerPixel};
	patchMode = arr[m_cmbPatchMode.GetCurSel()];

	// region threshold
	regionThreshold = m_spinRegionThreshold.GetPos32();

	iThreadCount = m_spinThreadCount.GetPos32();

	// sift models
	CString sPath;
	size_t tmp;
	m_txtSIFTKmeansModel.GetWindowText(sPath);
	wcstombs_s(&tmp, m_sSIFTKmeansModel, MAX_PATH * sizeof(char),
		sPath.GetBuffer(), MAX_PATH*sizeof(char));
	sPath.ReleaseBuffer();
	m_txtSIFTSVMModel.GetWindowText(sPath);
	wcstombs_s(&tmp, m_sSIFTSVMModel, MAX_PATH * sizeof(char),
		sPath.GetBuffer(), MAX_PATH*sizeof(char));
	sPath.ReleaseBuffer();

	return TRUE;
}

void CRefreeRetrievalDlg::DeleteHBITMAPs(CArray<HBITMAP> & arr)
{
	for(INT_PTR i = arr.GetCount() - 1; i >= 0; --i)
	{
		HBITMAP hBmp = arr.GetAt(i);
		if(hBmp)
			::DeleteObject(hBmp);
	}
	arr.RemoveAll();
}

/*==============================================================*/
// CRefreeRetrievalDlg message handlers
/*==============================================================*/
BOOL CRefreeRetrievalDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon

	m_imglstFrames.Create(32, 32, ILC_COLOR24, 0, 1);
	m_lstFrames.SetImageList(&m_imglstFrames, LVSIL_SMALL);
	m_lstFrames.SetImageList(&m_imglstFrames, LVSIL_NORMAL);
	m_vidAnalysis.SetGraphNotifier(GetSafeHwnd());

	m_txtClusterThreshold.SetWindowText(L"10.0");
	m_spinPatchSize.SetBuddy(&m_txtPatchSize);
	m_spinPatchSize.SetPos32(16);
	m_spinRegionThreshold.SetBuddy(&m_txtRegionThreshold);
	m_spinRegionThreshold.SetPos32(4);
	m_spinThreadCount.SetBuddy(&m_txtThreadCount);
	m_spinThreadCount.SetRange32(1, 100);
	m_spinThreadCount.SetPos32(5);
	m_cmbPatchMode.SetCurSel(0);

	TCHAR szBuffer[MAX_PATH];
	GetModuleFileName(NULL, szBuffer, MAX_PATH);
	CString sExecPath(szBuffer);
	sExecPath = sExecPath.Mid(0, sExecPath.ReverseFind(L'\\'));

	CString sFilePath;
	sFilePath = sExecPath + L"\\kmeans.txt";
	m_txtSIFTKmeansModel.SetWindowText(sFilePath);
	sFilePath = sExecPath + L"\\SVMModel.txt";
	m_txtSIFTSVMModel.SetWindowText(sFilePath);
	sFilePath = sExecPath + L"\\colorModel.xml";
	m_txtClusterModel.SetWindowText(sFilePath);

	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CRefreeRetrievalDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

void CRefreeRetrievalDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

HCURSOR CRefreeRetrievalDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

void CRefreeRetrievalDlg::OnBnClickedBtninputvideo()
{
	CString sFilter = L"MPG files (*.mpg)|*.mpg|WMV Files (*.wmv)|*.wmv|AVI files (*.avi)|*.avi|Supported video format|*.wmv;*.avi;*.mpg||";

	CFileDialog dlg(TRUE, L"*.mpg", NULL, 
		OFN_ENABLESIZING | OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST, 
		sFilter, this);
	if(dlg.DoModal() == IDOK)
	{
		m_txtInputVideo.SetWindowText(dlg.GetPathName());
	}
}

void CRefreeRetrievalDlg::OnBnClickedBtnclustermodel()
{
	CString sFilter = L"XML Files (*.xml)|*.xml||";

	CFileDialog dlg(TRUE, L"*.xml", NULL, 
		OFN_ENABLESIZING | OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST, 
		sFilter, this);
	if(dlg.DoModal() == IDOK)
	{
		m_txtClusterModel.SetWindowText(dlg.GetPathName());
	}
}

void CRefreeRetrievalDlg::OnBnClickedBtnsiftkmeansmodel()
{
	CString sFilter = L"Text Files (*.txt)|*.txt||";

	CFileDialog dlg(TRUE, L"*.txt", NULL, 
		OFN_ENABLESIZING | OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST, 
		sFilter, this);
	if(dlg.DoModal() == IDOK)
	{
		m_txtSIFTKmeansModel.SetWindowText(dlg.GetPathName());
	}
}

void CRefreeRetrievalDlg::OnBnClickedBtnsiftsvmmodel()
{
	CString sFilter = L"Text Files (*.txt)|*.txt||";

	CFileDialog dlg(TRUE, L"*.txt", NULL, 
		OFN_ENABLESIZING | OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST, 
		sFilter, this);
	if(dlg.DoModal() == IDOK)
	{
		m_txtSIFTSVMModel.SetWindowText(dlg.GetPathName());
	}
}

void CRefreeRetrievalDlg::OnBnClickedOk()
{
	CString sText;
	m_btnStart.GetWindowText(sText);

	if(sText.CompareNoCase(L"&Start") == 0)
	{
		CString sVideo, sClusterModel;
		double dClusterThreshold;
		int iPatchSize, iRegionThreshold, iThreadCount;
		PatchMode patchMode;

		if(!ReadParams(sVideo, sClusterModel, dClusterThreshold, 
			iPatchSize, patchMode, iRegionThreshold, iThreadCount))
			return;

		CTextFileRead f(sClusterModel);
		if(!f.IsOpen())
		{
			::MessageBox(GetSafeHwnd(), L"Cannot read the model file.",
				L"Error", MB_ICONERROR);
			m_txtClusterModel.SetFocus();
			return;
		}

		CString sXml;
		f.Read(sXml);
		f.Close();
		CMarkup xml(sXml);
		if(m_codeBook)
		{
			delete m_codeBook;
			m_codeBook = NULL;
		}
		m_codeBook = CCodeBook::Deserialize(xml);
		m_codeBook->SetThreshold(dClusterThreshold);

		m_lstFrames.DeleteAllItems();
		EmptyImgList(m_imglstFrames);
		DeleteHBITMAPs(m_arrKeyFrames);

		m_vidRetriever.Start(GetSafeHwnd(),
			m_codeBook, 
			m_histExtractor, 
			patchMode, 
			iPatchSize, 
			iRegionThreshold, 
			m_sSIFTKmeansModel, 
			m_sSIFTSVMModel, 
			iThreadCount);

		m_vidAnalysis.SetVideoFile(sVideo);
		m_iFrameCount = 0;
		m_vidAnalysis.Start();

		m_btnStart.SetWindowText(L"&Stop");
		m_btnPause.EnableWindow(TRUE);
		m_btnPause.SetWindowText(L"Pause");
	}
	else
	{
		m_vidAnalysis.Stop();
		m_btnStart.SetWindowText(L"&Start");
		m_btnPause.EnableWindow(FALSE);
		m_btnPause.SetWindowText(L"Pause");
	}
}

void CRefreeRetrievalDlg::OnBnClickedCancel()
{
	CString sText;
	m_btnStart.GetWindowText(sText);
	if(sText.CompareNoCase(L"&Stop") == 0)
	{
		m_vidAnalysis.Stop();
	}
	OnCancel();
}

void CRefreeRetrievalDlg::OnBnClickedBtnpause()
{
	CString sText;
	m_btnPause.GetWindowText(sText);
	
	m_vidAnalysis.Pause();

	if(sText.CompareNoCase(L"&Pause") == 0)
	{
		m_btnPause.SetWindowText(L"&Continue");
	}
	else
	{
		m_btnPause.SetWindowText(L"&Pause");
	}
}

LRESULT CRefreeRetrievalDlg::OnVideoAnaGraphNotify(WPARAM wParam, LPARAM lParam)
{
	m_vidAnalysis.OnGraphNotify();
	return 0;
}

LRESULT CRefreeRetrievalDlg::OnVideoAnaUserAnalysis(WPARAM wParam, LPARAM lParam)
{
	switch(wParam)
	{
	case VIDEOANA_WPARAM_FINISHED:
		{
			m_vidAnalysis.OnAnaFinished();

			CString strMsg;
			strMsg.Format(L"Process finished. %d frames total.", m_iFrameCount);
			::MessageBox(GetSafeHwnd(), strMsg, L"Info", MB_ICONINFORMATION);
			
			m_vidRetriever.CleanUp();

			m_btnStart.SetWindowText(L"&Start");
			m_btnPause.SetWindowText(L"&Pause");
			m_btnPause.EnableWindow(FALSE);
		}
		break;
	case VIDEOANA_WPARAM_NEWFRAME:
		{
			++m_iFrameCount;
			
			CString sFrames;
			sFrames.Format(L"Frames: %d", m_iFrameCount);
			m_lblFrames.SetWindowText(sFrames);

			HBITMAP hBmp = (HBITMAP)lParam;

			if(m_iFrameCount % 5 == 0)
			{
				TRACE(L"Sending frame #%d\r\n", m_iFrameCount);
				m_vidRetriever.AddFrame(m_iFrameCount, hBmp);
			}
			
			HBITMAP hBmpOld = m_picVideo.SetBitmap(hBmp);
			if(m_iFrameCount % 5 != 1)
			{
				::DeleteObject(hBmpOld);
			}
		}
		break;
	}
	return 0;
}

LRESULT CRefreeRetrievalDlg::OnRetrieverMessage(WPARAM wParam, LPARAM lParam)
{
	switch((UINT)wParam)
	{
	case CRetrieverMaster::NotifierWParamBitmapProcessed:
		{
			BitmapFrame* frame = (BitmapFrame*)lParam;
			CString sText;
			sText.Format(L"%d", frame->FrameIndex);
			int i = ::ImageList_Add(m_imglstFrames.GetSafeHandle(), 
				frame->Frame, NULL);
			m_lstFrames.InsertItem(m_lstFrames.GetItemCount(), sText, i);
			
			m_arrKeyFrames.Add(frame->Frame);
			delete frame;
		}
		break;
		
	}

	return 0;
}

void CRefreeRetrievalDlg::OnLvnItemActivateLstframes(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMITEMACTIVATE pNMIA = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
	*pResult = 0;

	if(pNMIA->iItem < 0 || pNMIA->iItem > m_arrKeyFrames.GetCount())
		return;

	CViewBitmapDlg* dlg = new CViewBitmapDlg();
	dlg->SetBitmap(m_arrKeyFrames[pNMIA->iItem]);
	dlg->Create(CViewBitmapDlg::IDD, NULL);
	dlg->ShowWindow(SW_SHOW);
}
